﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using LLoger;
using LimitatorInterfaces;
using LimitatorInterfaces.CorrectServices;
using LimitatorInterfaces.LoadServices;
using LimitatorInterfaces.UnloadServices;
using LimitEntityList = System.Collections.Generic.List<LimitatorInterfaces.LimitEntity>;

namespace Limitator
{
    public class LimitManager : ServiceBase
    {
        private readonly string _configPath;
        private readonly ILogWriter _logWriter;
        private ILoadService _loadSvc;
        private ICorrectionLimitService _correctionSvc;
        private IUnloadService _unloadService;
        private LimitEntityList _limitsTable = new LimitEntityList();

        public LimitManager(string configPath, ILogWriter logWriter, Dictionary<string, object> serviceParams = null)
            : base(configPath, logWriter, serviceParams)
        {
            _configPath = configPath;
            _logWriter = logWriter;
        }

        private void CreateLoadService()
        {

            string path = GetSettingsValue(Res.LoadService);

            var factory = InstantiateType<LoadServiceFactory>(path);

            _loadSvc = factory.CreateLoadService(_configPath, _logWriter);

        }

        private void CreateCorrectionService()
        {

            string path = GetSettingsValue(Res.CorrectionService);

            var factory = InstantiateType<CorrectionServiceFactory>(path);

            _correctionSvc = factory.CreateCorrectionService(_configPath, _logWriter);

        }

        private void CreateUnloadService()
        {

            string path = GetSettingsValue(Res.UnloadService);

            var factory = InstantiateType<UnloadServiceFactory>(path);

            _unloadService = factory.CreateUnloadService(_configPath, _logWriter);


        }

        private T InstantiateType<T>(string assemblyPath)
        {
            if (!File.Exists(assemblyPath))
                throw new FileNotFoundException("Сборка не найдена!", assemblyPath);

            Type factType = typeof(T);

            Exception errObj = null;
            string msg = "";

            try
            {
                var asm = Assembly.Load(AssemblyName.GetAssemblyName(assemblyPath));

                var type = asm.GetExportedTypes().SingleOrDefault(t => t.BaseType == factType);

                if (type == null)
                    throw new LoadServicesAssemblyException("Не обнаружен класс инициализации сервиса");

                return (T)Activator.CreateInstance(type);
            }
            catch (FileLoadException ex)
            {
                msg = "Ошибка при загрузке сервисной библиотеки " + assemblyPath;
                errObj = new LoadServicesAssemblyException(msg, ex);
            }
            catch (BadImageFormatException ex)
            {
                msg = "Ошибка при загрузке сервисной библиотеки " + assemblyPath;
                errObj = new LoadServicesAssemblyException(msg, ex);
            }
            catch (LoadServicesAssemblyException ex)
            {
                errObj = ex;
            }
            catch (Exception ex)
            {
                msg = "Неопознанное исключение при загрузке или инициализации сервиса";
                errObj = new LoadServicesAssemblyException(msg, ex);
            }

            //LogWriter.WriteLine(errObj, msg);
            throw errObj;

        }

        public void InitializeServices()
        {
            try
            {
                CreateLoadService();
                CreateCorrectionService();
                CreateUnloadService();
            }

            catch (Exception ex)
            {
                LogWriter.WriteLine(ex, "Ошибка при иницализации сервисов");
            }
        }

        public void StartProcess()
        {
            _loadSvc.LoadLimits(_limitsTable);

            _correctionSvc.LoadSourceLimits(_limitsTable);
            _correctionSvc.LoadCorrections();
            _correctionSvc.CorrectLimits();

            _unloadService.LoadSourceLimits(_limitsTable);
            _unloadService.UnloadLimits();
        }
    }
}
